package br.com.android.serialization.api;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;
import java.util.ArrayList;
import java.util.List;

public class GenericDAO {

	private GenericDAO() {
		if (GenericDAO.ID == null)
			GenericDAO.ID = deserializeID();
		if (GenericDAO.INDEX == null)
			GenericDAO.INDEX = deserializeIndex();
	}
	private final static class LazySingleton {
		private final static GenericDAO INSTANCE = new GenericDAO();
	}
	private static final GenericDAO getInstance() {
		return LazySingleton.INSTANCE;
	}
	
	private static Integer 		 ID    = new Integer(0);
	private static List<Integer> INDEX = new ArrayList<Integer>();

	/**
	 * CRUD - object
	 */
	/* CREATE OBJECT */
	public <T extends BaseVO> boolean createObject (T object) {
		GenericDAO.ID = object.getId();
		INDEX.add(GenericDAO.ID);
		return serialize(assignNewID(object), Config.object_storage+GenericDAO.ID);
	}
	/* READ OBJECT */
	public <T extends BaseVO> T readObject(Integer id) {
		GenericDAO.ID = id;
		return (T) deserialize(Config.object_storage+GenericDAO.ID);
	}
	/* UPDATE OBJECT */
	public <T extends BaseVO> boolean updateObject(T object) {
		GenericDAO.ID = object.getId();
		return serialize(object, Config.object_storage+GenericDAO.ID);
	}
	/* DELETE OBJECT */
	public boolean deleteObject(Integer id) {
		GenericDAO.ID = deserializeID();
		GenericDAO.INDEX.remove(id);
		return new File(Config.object_storage+id).delete();
	}
	
	/**
	 * CRUD - list
	 */
	/* CREATE LIST */
	
	/* READ LIST */
	/* UPDATE LIST */
	/* DELETE LIST */
	
	private <T extends BaseVO> boolean serializeList (List<T> list) {
		return serialize(list, Config.object_storage);
	}
	
//	private <T extends BaseVO> boolean serializeObject (T object) {
//		return serialize(object, Config.data+object.getId());
//	}
	
	protected <T extends BaseVO> T deserializeObject (Integer id) {
		return (T) deserialize(Config.object_storage+id);
	}
	
	protected <T extends BaseVO> List<T> deserializeList () {
		return (List<T>) deserialize(Config.object_storage+GenericDAO.ID);
	}
	
	/**
	 * GENERATE NEW ID
	 */
	private <T extends BaseVO> T assignNewID (T object) {
		if (object != null)
			if (object.getId() != null) {
				ID = deserializeID()+1;
				serializeID (ID);
				object.setId(ID);
			}
		return object;
	}
	
	/**
	 * Serialize - Deserialize INDEX
	 */
	protected boolean serializeIndex() {
		return serialize(INDEX, Config.index);
	}
	protected List<Integer> deserializeIndex() {
		return (List<Integer>) deserialize(Config.index);
	}
	
	/**
	 * Serialize - Deserialize ID
	 */
	protected boolean serializeID (Integer id) {
		return serialize(id, Config.id);
	}
	protected Integer deserializeID () {
		return (Integer) deserialize(Config.id);
	}
	
	/**
	 * Serializer - Deserializer
	 */
	private boolean serialize(Object object, String location) {
		boolean state = false;
		
		FileOutputStream   fos;
		ObjectOutputStream oos;
		try {
			fos = new FileOutputStream   (location);
			oos = new ObjectOutputStream (fos);
	        
	        if (object != null)
	        	oos.writeObject (object);
	        
	        oos.close ();
	        state = true;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return state;
	}
	private Object deserialize(String location) {
		FileInputStream   fis;
		ObjectInputStream ois;
		
		Object object = null;
		
		try {
			fis = new FileInputStream   (location);
			ois = new ObjectInputStream (fis);
			
			object = ois.readObject();
			ois.close();
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (StreamCorruptedException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return object;
	}
}
